#include "../../../dxhead/dxegheader.h"
#include "../inc/xDxInput.h"

using namespace Sky;

xDxInput::xDxInput():
mpDI(vNull),
mpKeyboard(vNull),
mpMouse(vNull),
mnKeyElements(0),
mnMouseElements(0),
mpAcquireKeyboard(vNull),
mpAcquireMouse(vNull),
mCurDiks(0),
mCurDims(0),
mHinstance(vNull),
mHWnd(vNull),
mbInitliseCalled(vFalse)
{

}
xDxInput::~xDxInput()
{
	Finalise();
}
HRESULT xDxInput::Initlise(HINSTANCE hinst,HWND hWnd,TUint DEVTYPE_,TUint DISCL_,TUint DINTYPE_)
{
	mbInitliseCalled = vTrue;
	mDinType = DINTYPE_;
	mHWnd = hWnd == vNull ? ::GetActiveWindow() : hWnd;
	mHinstance = hinst == vNull ? (HINSTANCE)::GetModuleHandle(vNull) : hinst;
	myDiV_Ret_hr_M(DirectInput8Create(mHinstance,DIRECTINPUT_VERSION, IID_IDirectInput8, (TVoid**)&mpDI, vNull),XE_APICALL);
	if(XE_OK != CreateKeyboard(DISCL_,DINTYPE_) ||
	   XE_OK != CreateMouse(DISCL_,DINTYPE_))
	{
		myTrace0A(M,"xDxInput::Initlise() failed");
		return XE_APICALL;
	}
	
	if(DINTYPE_==DINTYPE_Immediate)
	{
		mpAcquireKeyboard=&xDxInput::AcquireKeyboardIMME;
		mpAcquireMouse=&xDxInput::AcquireMouseIMME;
	}
	else if(DINTYPE_==DINTYPE_Buffered)
	{
		mpAcquireKeyboard=&xDxInput::AcquireKeyboardBUFF;
		mpAcquireMouse=&xDxInput::AcquireMouseBUFF;
	}
	else if(DINTYPE_==(DINTYPE_Immediate|DINTYPE_Buffered))
	{
		mpAcquireKeyboard=&xDxInput::AcquireKeyboardIMMEBUFF;
		mpAcquireMouse=&xDxInput::AcquireMouseIMMEBUFF;
	}
	return XE_OK;
}
HRESULT	xDxInput::SetCooperativeLevel(TUint DEVTYPE_,TUint DISCL_) {

	if(DEVTYPE_ & DEVTYPE_Mouse)
	{
		if(mpMouse)mpMouse->Unacquire();
		SAFE_RELEASE(mpMouse);
		return CreateMouse(DISCL_,mDinType);
	}
	if(DEVTYPE_ & DEVTYPE_Keyboard)
	{
		if(mpKeyboard)mpKeyboard->Unacquire();
		SAFE_RELEASE(mpKeyboard);
		return CreateKeyboard(DISCL_,mDinType);
	}
	return XE_ARGUMENT;
}
void	xDxInput::Finalise()
{
	if(mpKeyboard)mpKeyboard->Unacquire();
	if(mpMouse)mpMouse->Unacquire();
	SAFE_RELEASE(mpMouse);
	SAFE_RELEASE(mpKeyboard);
	SAFE_RELEASE(mpDI);
}
TResult AcquireDev(LPDIRECTINPUTDEVICE8 pDev)
{
	HRESULT hr;
	hr = pDev->Acquire();
	while( hr == DIERR_INPUTLOST )hr = pDev->Acquire();
	if( hr == DIERR_OTHERAPPHASPRIO || hr == DIERR_NOTACQUIRED ) 
		return XE_APICALL;
	return XE_OK;
}
TBool xDxInput::AcquireKeyboardIMME()
{
	if(mpKeyboard)
	{
		mCurDiks ^= 0x1;
		if( FAILED(mpKeyboard->GetDeviceState(sizeof(mdiks[mCurDiks]),&mdiks[mCurDiks])) ) 
		{
			if(FAILED(AcquireDev(mpKeyboard)))return vFalse;
			if(FAILED(mpKeyboard->GetDeviceState(sizeof(mdiks[mCurDiks]),&mdiks[mCurDiks])))return vFalse;
		}
	}
	return vTrue;
}
TBool xDxInput::AcquireMouseIMME()
{
	if(mpMouse)
	{
		mCurDims ^= 0x1;
		if( FAILED(mpMouse->GetDeviceState(sizeof(mdims2[mCurDims]),&mdims2[mCurDims])) ) 
		{
			if(FAILED(AcquireDev(mpMouse)))return vFalse;
			if(FAILED(mpMouse->GetDeviceState(sizeof(mdims2[mCurDims]),&mdims2[mCurDims])))return vFalse;
		}
	}
	return vTrue;
}
TBool	   xDxInput::IsMouseJustPressedIMME(TUint DIM_)
{
	TUint iPre = mCurDims ^ 0x1;
	return (mdims2[mCurDims].rgbButtons[DIM_] & 0x80) > (mdims2[iPre].rgbButtons[DIM_] & 0x80);
}
TBool	   xDxInput::IsMouseJustReleasedIMME(TUint DIM_)
{
	TUint iPre = mCurDims ^ 0x1;
	return (mdims2[mCurDims].rgbButtons[DIM_] & 0x80) < (mdims2[iPre].rgbButtons[DIM_] & 0x80);
}
TBool	   xDxInput::IsKeyJustPressedIMME(TUint DIK_)
{
	TUint iPre = mCurDiks ^ 0x1;
	return (mdiks[mCurDims][DIK_] & 0x80) > (mdiks[iPre][DIK_] & 0x80);
}
TBool	   xDxInput::IsKeyJustReleasedIMME(TUint DIK_)
{
	TUint iPre = mCurDiks ^ 0x1;
	return (mdiks[mCurDims][DIK_] & 0x80) < (mdiks[iPre][DIK_] & 0x80);
}
TBool xDxInput::AcquireKeyboardBUFF()
{
	if(mpKeyboard)
	{
		mnKeyElements = KEYBOARD_BUFFER_COUNT;
		if( FAILED(mpKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),mKeyboard, &mnKeyElements, 0 ))) 
		{
			if(FAILED(AcquireDev(mpKeyboard)))return vTrue;
			if(FAILED(mpKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),mKeyboard, &mnKeyElements, 0 )))return vFalse;
		}
	}
	if(mnKeyElements!=0)return vTrue;
	return vFalse;
}
TBool xDxInput::AcquireMouseBUFF()
{
	if(mpMouse)
	{
		mnMouseElements = MOUSE_BUFFER_COUNT;
		ZeroMemory(mMouse,sizeof(mMouse));
		if( FAILED(mpMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),mMouse, &mnMouseElements, 0 )) ) 
		{
			if(FAILED(AcquireDev(mpMouse)))return vFalse;
			if(FAILED(mpMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),mMouse, &mnMouseElements, 0 )))return vFalse;
		}
	}
	if(mnMouseElements!=0)return vTrue;
	return vFalse;
}
TBool xDxInput::AcquireKeyboardIMMEBUFF()
{
	if(FAILED(AcquireKeyboardIMME()))return vFalse;
	if(FAILED(AcquireKeyboardBUFF()))return vFalse;
	return vTrue;
}
TBool xDxInput::AcquireMouseIMMEBUFF()
{
	if(FAILED(AcquireMouseIMME()))return vFalse;
	if(FAILED(AcquireMouseBUFF()))return vFalse;
	return vTrue;
}
TBool xDxInput::PeekInputMessage()
{
	TBool ret;
	if(mpAcquireKeyboard == vNull &&
		mpAcquireMouse == vNull) {
			if(!mbInitliseCalled)
				Initlise();
			else	return vFalse;
		}
	

	ret = PeekKeyboard();
	ret |= PeekMouse();
	return ret;
}
TVoid xDxInput::DispatchInputMessage()
{
	
}

TBool xDxInput::IsMouseJustPressedBUFF(TUint DIM_)
{
	TUint i = 0;
	TUint DIMOFS_ = DIM_ + DIM_BASE;
	for(;i<mnMouseElements;i++){
		if(DIMOFS_ == mMouse[ i ].dwOfs){
			if((mMouse[ i ].dwData & 0x80) != 0) {
				return vTrue;
			}
		}
	}
	return vFalse;
}

TBool xDxInput::IsMouseJustReleasedBUFF( TUint DIM_ )
{
	TUint i = 0;
	TUint DIMOFS_ = DIM_ + DIM_BASE;
	for(;i<mnMouseElements;i++){
		if(DIMOFS_ == mMouse[ i ].dwOfs){
			if((mMouse[ i ].dwData & 0x80) == 0) {
				return vTrue;
			}
		}
	}
	return vFalse;
}

TBool xDxInput::IsKeyJustPressedBUFF( TUint DIK_ )
{
	TUint i = 0;
	for(;i<mnKeyElements;i++){
		if(DIK_ == mKeyboard[ i ].dwOfs){
			if((mKeyboard[ i ].dwData & 0x80) != 0) {
				return vTrue;
			}
		}
	}
	return vFalse;
}

TBool xDxInput::IsKeyJustReleasedBUFF( TUint DIK_ )
{
	TUint i = 0;
	for(;i<mnKeyElements;i++){
		if(DIK_ == mKeyboard[ i ].dwOfs){
			if((mKeyboard[ i ].dwData & 0x80 ) == 0) {
				return vTrue;
			}
		}
	}
	return vFalse;
}
TUint	   xDxInput::GetMouseDltaXBUFF()
{
	TUint d = 0;
	for(TUint i = 0;i<mnKeyElements;i++){
		if(DIMOFS_X == mMouse[ i ].dwOfs){
			d += mMouse[i].dwData;
		}
	}
	return d;
}
TUint	   xDxInput::GetMouseDltaYBUFF()
{
	TUint d = 0;
	for(TUint i = 0;i<mnKeyElements;i++){
		if(DIMOFS_Y == mMouse[ i ].dwOfs){
			d += mMouse[i].dwData;
		}
	}
	return d;
}
TUint	   xDxInput::GetMouseDltaZBUFF()
{
	TUint d = 0;
	for(TUint i = 0;i<mnKeyElements;i++){
		if(DIMOFS_Z == mMouse[ i ].dwOfs){
			d += mMouse[i].dwData;
		}
	}
	return d;
}

TBool xDxInput::PeekKeyboard()
{
	if(mpAcquireKeyboard)
		return (this->*mpAcquireKeyboard)();
	return vFalse;
}

TBool xDxInput::PeekMouse()
{
	if(mpAcquireMouse)
		return (this->*mpAcquireMouse)();
	return vFalse;
}

TResult xDxInput::CreateKeyboard(TUint DISCL_,TUint DINTYPE_ )
{
	{
		myDiV_Ret_hr_M(mpDI->CreateDevice( GUID_SysKeyboard, &mpKeyboard, vNull ),XE_APICALL);
		myDiV_Ret_hr_M(mpKeyboard->SetDataFormat( &c_dfDIKeyboard ),XE_APICALL);
		if(mHWnd)
			myDiV_Ret_hr_M(mpKeyboard->SetCooperativeLevel( mHWnd, DISCL_ ),XE_APICALL);

		if(DINTYPE_&DINTYPE_Buffered)
		{
			DIPROPDWORD dipdw;
			dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
			dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
			dipdw.diph.dwObj        = 0;
			dipdw.diph.dwHow        = DIPH_DEVICE;
			dipdw.dwData            = KEYBOARD_BUFFER_COUNT; // Arbitary buffer size
			myDiV_Ret_hr_M(mpKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ),XE_APICALL );
		}
		mpKeyboard->Acquire();
	}
	return XE_OK;
}

TResult Sky::xDxInput::CreateMouse( TUint DISCL_,TUint DINTYPE_ )
{
	{
		myDiV_Ret_hr_M(mpDI->CreateDevice( GUID_SysMouse, &mpMouse, vNull ),XE_APICALL );
		myDiV_Ret_hr_M(mpMouse->SetDataFormat( &c_dfDIMouse2 ),XE_APICALL);
		if(mHWnd)
			myDiV_Ret_hr_M(mpMouse->SetCooperativeLevel( mHWnd, DISCL_ ),XE_APICALL);
		if(DINTYPE_&DINTYPE_Buffered)
		{
			DIPROPDWORD dipdw;
			dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
			dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
			dipdw.diph.dwObj        = 0;
			dipdw.diph.dwHow        = DIPH_DEVICE;
			dipdw.dwData            = MOUSE_BUFFER_COUNT; // Arbitary buffer size
			myDiV_Ret_hr_M(mpMouse->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ),XE_APICALL );
		}
		mpMouse->Acquire();
	}
	return XE_OK;
}